home *** CD-ROM | disk | FTP | other *** search
/ Nebula 2 / Nebula Two.iso / Apps / ScreenSavers / SpaceSaver / Source / UserPath.m < prev   
Encoding:
Text File  |  1995-06-12  |  8.8 KB  |  328 lines

  1. /* 
  2.  * UserPath.m by Bruce Blumberg, NeXT Computer, Inc.
  3.  *
  4.  * You may freely copy,distribute and re-use the code in this example.
  5.  * NeXT disclaims any warranty of any kind, expressed or implied, as
  6.  * to its fitness for any particular purpose
  7.  *
  8.  */
  9.  
  10. #import "UserPath.h"
  11. #import <mach/mach_init.h>
  12. #import <appkit/graphics.h>
  13. #import <appkit/errors.h>
  14. #import <math.h>
  15. #import <libc.h>
  16.  
  17. static NXZone *upZone = NULL;
  18.  
  19. NXZone *userPathZone()
  20. /* Creates a unique zone for use by all user paths */
  21. {
  22.     if (!upZone) upZone = NXCreateZone(vm_page_size, vm_page_size, 1);
  23.  
  24.     return upZone;
  25. }
  26.  
  27. UserPath *newUserPath() // Creates a new User Path in the zone returned by userPathZone
  28. {
  29.     UserPath *up;
  30.  
  31.     up = (UserPath *) NXZoneMalloc(userPathZone(), sizeof(UserPath));
  32.     up->max = 32;
  33.     up->points = (float *) NXZoneMalloc(userPathZone(), sizeof(float) * up->max);
  34.     up->ops = (char *) NXZoneMalloc(userPathZone(), (2 + (up->max / 2)) * sizeof(char));
  35.     up->ping = NO;
  36.  
  37.     return up;
  38. }
  39.  
  40. void freeUserPath(UserPath *up) // Frees User Path and its associated buffers
  41. {
  42.     free(up->points);
  43.     free(up->ops);
  44.     free(up);
  45.  
  46.     return;
  47. }
  48.  
  49. void growUserPath(UserPath *up)
  50. /*
  51.  * Grows the associated buffers as necessary.  Buffer size doubles on each
  52.  * call.  You never need to call grow directly as it is called as needed by the
  53.  * methods and functions which add elements into the buffer
  54.  */
  55. {
  56.  /* double the size of the internal buffers */
  57.     up->max *= 2;
  58.     up->points = (float *) NXZoneRealloc(userPathZone(), up->points, sizeof(float) * up->max);
  59.     up->ops = (char *) NXZoneRealloc(userPathZone(), up->ops, (2 + (up->max / 2)) * sizeof(char));
  60.  
  61.     return;
  62. }
  63.  
  64. void beginUserPath(UserPath *up, BOOL cache)
  65. /*
  66.  * Call this to start generating a user path.  The cache argument specifies if
  67.  * you want the user path cached at the server (i.e. dps_ucache).  In either
  68.  * case, the UserPath object will automatically calculate the bounding box for
  69.  * the path and add the dps_setbbox operator.
  70.  */
  71. {
  72.     up->numberOfPoints = up->numberOfOps = 0;
  73.     up->cp.x = up->cp.y = 0;
  74.     up->bbox[0] = up->bbox[1] = 1.0e6;
  75.     up->bbox[2] = up->bbox[3] = -1.0e6;
  76.     if (cache) up->ops[up->numberOfOps++] = dps_ucache;
  77.     up->ops[up->numberOfOps++] = dps_setbbox;
  78.     up->opForUserPath = 0;
  79.  
  80.     return;
  81. }
  82.  
  83. void endUserPath(UserPath *up, int op)
  84. /*
  85.  * Call this to stop filling the path.  Note this does not send the userpath to
  86.  * the server -- use sendUserPath.  The op argument should be one of the
  87.  * following:
  88.  *    dps_uappend, dps_ufill ,dps_ueofill, dps_ustroke, dps_ustrokepath,
  89.  *    dps_inufill, dps_inueofill, dps_inustroke, dps_def, dps_put.
  90.  * These are defined in <dpsclient/dpsNext.h.
  91.  */
  92. {
  93.     up->opForUserPath = op;
  94.  
  95.     return;
  96. }
  97.  
  98. int sendUserPath(UserPath *up)
  99. /*
  100.  * Call this to send the path down to the server.  If ping==YES (set via
  101.  * debug:), the function will send an NXPing() after the Path.  In any event,
  102.  * code is bracketed by a NX_DURING ... NX_HANDLER construct which will try to
  103.  * catch postscript errors.  If ping==NO (the default) it is unlikely to catch
  104.  * errors, with ping==YES it will.  Whether you can recover or not is another
  105.  * matter.  sendUserPath returns 0 on success and -1 on failure.  If no previous
  106.  * endUserPath: has been sent, will return -2 and will not send the path to the
  107.  * server.
  108.  */
  109. {
  110.     NXHandler exception;
  111.  
  112.     exception.code = 0;
  113.     if (up->opForUserPath != 0) {
  114.         NX_DURING
  115.             DPSDoUserPath(up->points, up->numberOfPoints, dps_float, up->ops, up->numberOfOps, up->bbox, up->opForUserPath);
  116.             if (up->ping) NXPing();
  117.         NX_HANDLER
  118.             exception = NXLocalHandler;
  119.         NX_ENDHANDLER
  120.         if (exception.code) {
  121.             NXReportError(&exception);
  122.             if (exception.code == dps_err_ps) return -1;
  123.             }
  124.         else return 0;
  125.         }
  126.  
  127.     return -1;
  128. }
  129.  
  130. void checkBoundingBox(UserPath *up, float x, float y)
  131. /* Checks if bounding box needs to be enlarged based on x and y */
  132. {
  133.     if (x < up->bbox[0]) up->bbox[0] = x;
  134.     if (y < up->bbox[1]) up->bbox[1] = y;
  135.     if (x > up->bbox[2]) up->bbox[2] = x;
  136.     if (y > up->bbox[3]) up->bbox[3] = y;
  137.  
  138.     return;
  139. }
  140.  
  141. void addPts(UserPath *up, float x, float y)
  142. /* adds x and y to user path.  Updates bounding box as necessary */
  143. {
  144.     if (!((up->numberOfPoints + 2) < up->max)) growUserPath(up);
  145.  
  146.     up->points[up->numberOfPoints++] = x;
  147.     up->points[up->numberOfPoints++] = y;
  148.     checkBoundingBox(up, x, y);
  149.  
  150.     return;
  151. }
  152.  
  153. void addOp(UserPath *up, int op)
  154. /*
  155.  * adds operator to user path.  Operator should be one of the following:
  156.  *     dps_moveto, dps_rmoveto, dps_lineto, dps_rlineto, dps_curveto,
  157.  *    dps_rcurveto, dps_arc, dps_arcn, dps_arct, dps_closepath.
  158.  */
  159. {
  160.     up->ops[up->numberOfOps++] = op;
  161.  
  162.     return;
  163. }
  164.  
  165. void add(UserPath *up, int op, float x, float y)
  166. /*
  167.  * adds operator and x and y to user path.  Operator should be one of the
  168.  * operators above
  169.  */
  170. {
  171.     if (!((up->numberOfPoints + 2) < up->max)) growUserPath(up);
  172.  
  173.     up->ops[up->numberOfOps++] = op;
  174.     up->points[up->numberOfPoints++] = x;
  175.     up->points[up->numberOfPoints++] = y;
  176.     checkBoundingBox(up, x, y);
  177.  
  178.     return;
  179. }
  180.  
  181. void UPmoveto(UserPath *up, float x, float y)
  182. /* adds <x y moveto> to user path and updates bounding box */
  183. {
  184.     add(up, dps_moveto, x, y);
  185.     up->cp.x = x;
  186.     up->cp.y = y;
  187.  
  188.     return;
  189. }
  190.  
  191. void UPrmoveto(UserPath *up, float x, float y)
  192. /* adds <x y rmoveto> to user path and updates bounding box */
  193. {
  194.     if (!((up->numberOfPoints + 2) < up->max)) growUserPath(up);
  195.     
  196.     up->ops[up->numberOfOps++] = dps_rmoveto;
  197.     up->points[up->numberOfPoints++] = x;
  198.     up->points[up->numberOfPoints++] = y;
  199.     up->cp.x += x;
  200.     up->cp.y += y;
  201.     checkBoundingBox(up, up->cp.x, up->cp.y);
  202.  
  203.     return;
  204. }
  205.  
  206. void UPlineto(UserPath *up, float x, float y)
  207. /* adds <x y lineto> to user path and updates bounding box */
  208. {
  209.     add(up, dps_lineto, x, y);
  210.     up->cp.x = x;
  211.     up->cp.y = y;
  212.     
  213.     return;
  214. }
  215.  
  216. void UPrlineto(UserPath *up, float x, float y)
  217. /* adds <x y rlineto> to user path and updates bounding box */
  218. {
  219.     if (!((up->numberOfPoints + 2) < up->max)) growUserPath(up);
  220.  
  221.     up->ops[up->numberOfOps++] = dps_rlineto;
  222.     up->points[up->numberOfPoints++] = x;
  223.     up->points[up->numberOfPoints++] = y;
  224.     up->cp.x += x;
  225.     up->cp.y += y;
  226.     checkBoundingBox(up, up->cp.x, up->cp.y);
  227.  
  228.     return;
  229. }
  230.  
  231. void UPcurveto(UserPath *up, float x1, float y1, float x2, float y2, float x3, float y3)
  232. /* adds <x1 y1 x2 y2 curveto> to user path and updates bounding box */
  233. {
  234.     addPts(up, x1, y1);
  235.     addPts(up, x2, y2);
  236.     add(up, dps_curveto, x3, y3);
  237.     up->cp.x = x3;
  238.     up->cp.y = y3;
  239.  
  240.     return;
  241. }
  242.  
  243. void UPrcurveto(UserPath *up, float dx1, float dy1, float dx2, float dy2, float dx3, float dy3)
  244. /* adds <x1 y1 x2 y2 rcurveto> to user path and updates bounding box */
  245. {
  246.     if (!((up->numberOfPoints + 6) < up->max)) growUserPath(up);
  247.  
  248.     up->ops[up->numberOfOps++] = dps_rcurveto;
  249.     up->points[up->numberOfPoints++] = dx1;
  250.     up->points[up->numberOfPoints++] = dy1;
  251.     up->points[up->numberOfPoints++] = dx2;
  252.     up->points[up->numberOfPoints++] = dy2;
  253.     up->points[up->numberOfPoints++] = dx3;
  254.     up->points[up->numberOfPoints++] = dy3;
  255.     checkBoundingBox(up, up->cp.x + dx1, up->cp.y + dy1);
  256.     checkBoundingBox(up, up->cp.x + dx2, up->cp.y + dy2);
  257.     checkBoundingBox(up, up->cp.x + dx3, up->cp.y + dy3);
  258.     up->cp.x = dx3;
  259.     up->cp.y = dy3;
  260.  
  261.     return;
  262. }
  263.  
  264. void UParc(UserPath *up, float x, float y, float r, float ang1, float ang2)
  265. /* adds <x y r ang1 ang2 arc> to user path and updates bounding box */
  266. {
  267.     if (!((up->numberOfPoints + 5) < up->max)) growUserPath(up);
  268.  
  269.     up->ops[up->numberOfOps++] = dps_arc;
  270.     up->points[up->numberOfPoints++] = x;
  271.     up->points[up->numberOfPoints++] = y;
  272.     up->points[up->numberOfPoints++] = r;
  273.     up->points[up->numberOfPoints++] = ang1;
  274.     up->points[up->numberOfPoints++] = ang2;
  275.     checkBoundingBox(up, x + r, y + r);
  276.     checkBoundingBox(up, x - r, y - r);
  277.     up->cp.x = x + cos(ang2 / 57.3) * r;
  278.     up->cp.y = y + sin(ang2 / 57.3) * r;
  279.  
  280.     return;
  281. }
  282.  
  283. void UParcn(UserPath *up, float x, float y, float r, float ang1, float ang2)
  284. /* adds <x y r ang1 ang2 arcn> to user path and updates bounding box */
  285. {
  286.     if (!((up->numberOfPoints + 5) < up->max)) growUserPath(up);
  287.  
  288.     up->ops[up->numberOfOps++] = dps_arcn;
  289.     up->points[up->numberOfPoints++] = x;
  290.     up->points[up->numberOfPoints++] = y;
  291.     up->points[up->numberOfPoints++] = r;
  292.     up->points[up->numberOfPoints++] = ang1;
  293.     up->points[up->numberOfPoints++] = ang2;
  294.     checkBoundingBox(up, x + r, y + r);
  295.     checkBoundingBox(up, x - r, y - r);
  296.     up->cp.x = x + cos(ang2 / 57.3) * r;
  297.     up->cp.y = y + sin(ang2 / 57.3) * r;
  298.  
  299.     return;
  300. }
  301.  
  302. void UParct(UserPath *up, float x1, float y1, float x2, float y2, float r)
  303. /* adds <x1 y1 x2 y2 r arct> to user path and updates bounding box */
  304. {
  305.     if (!((up->numberOfPoints + 5) < up->max)) growUserPath(up);
  306.  
  307.     up->ops[up->numberOfOps++] = dps_arcn;
  308.     up->points[up->numberOfPoints++] = x1;
  309.     up->points[up->numberOfPoints++] = y1;
  310.     up->points[up->numberOfPoints++] = x2;
  311.     up->points[up->numberOfPoints++] = y2;
  312.     up->points[up->numberOfPoints++] = r;
  313.     checkBoundingBox(up, x1, y1);
  314.     checkBoundingBox(up, x2, y2);
  315.     up->cp.x = x2;
  316.     up->cp.y = y2;
  317.  
  318.     return;
  319. }
  320.  
  321. void closePath(UserPath *up)
  322. /* adds <closepath> to user path and updates bounding box */
  323. {
  324.     up->ops[up->numberOfOps++] = dps_closepath;
  325.  
  326.     return;
  327. }
  328.